package com.yangxk.kadmin.generator.engine;

import com.yangxk.kadmin.generator.field.Field;
import com.yangxk.kadmin.generator.genfile.GeneratorFile;
import com.yangxk.kadmin.generator.constant.Const;
import com.yangxk.kadmin.generator.internal.ConfigInternal;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;

public abstract class AbstractTemplateEngine {

    protected static Map<String, Object> objMap = new HashMap<>();

    private ConfigInternal configInternal;
    private VelocityEngine velocityEngine;

    protected List<GeneratorFile> generatorFiles = new ArrayList<>();

    public void init(ConfigInternal configInternal) {
        this.configInternal = configInternal;

        getObjMap();

        Properties p = new Properties();
        p.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        p.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
        p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        p.setProperty("file.resource.loader.unicode", "true");
        velocityEngine = new VelocityEngine(p);
    }

    public List<GeneratorFile> generator() {
        generatorMapper(configInternal);
        generatorXml(configInternal);
        generatorService(configInternal);
        generatorServiceImpl(configInternal);
        generatorController(configInternal);
        generatorPo(configInternal);
        generatorPojo(configInternal);
        generatorVo(configInternal);
        generatorQueryForm(configInternal);
        generatorEditForm(configInternal);
        generatorVuePage(configInternal);
        generatorVueApi(configInternal);
        generatorVueRoute(configInternal);

        return generatorFiles;
    }

    protected void getObjMap() {
        ConfigInternal config = configInternal;
        objMap.put("tableName", config.getTableName());
        objMap.put("modelName", config.getModelName());
        objMap.put("modelNameLower", config.getModelNameLower());
        objMap.put("zhModelName", config.getZhModelName());
        objMap.put("pkField", config.getPkField());
        objMap.put("dataScope", config.isDataScope());
        objMap.put("queryAll", config.isQueryAll());
        objMap.put("relate", config.isRelate());
        objMap.putAll(config.getPackageInfo());
        objMap.putAll(config.getSuperInfo());
        objMap.putAll(config.getNames());
        objMap.putAll(config.getRequestUrl());
        objMap.putAll(config.getAuthCode());
        objMap.put(Const.PO_FIELDS, config.getPoFields());
        objMap.put(Const.POJO_FIELDS, config.getPojoFields());
        objMap.put(Const.VO_FIELDS, config.getVoFields());
        objMap.put(Const.QUERY_FORM_FIELDS, config.getQueryFormFields());
        objMap.put(Const.EDIT_FORM_FIELDS, config.getEditFormFields());
        objMap.put(Const.PO_IMPORTED, config.getPoImported());
        objMap.put(Const.POJO_IMPORTED, config.getPojoImported());
        objMap.put(Const.VO_IMPORTED, config.getVoImported());
        objMap.put(Const.QUERY_FORM_IMPORTED, config.getQueryFormImported());
        objMap.put(Const.EDIT_FORM_IMPORTED, config.getEditFormImported());

        objMap.put("relateTableAlias", config.getRelateTableAlias());
        objMap.put("tableAlias", config.getTableAlias());
        objMap.put("relateTable", config.getRelateTable());
        objMap.put("relateTableField", config.getRelateTableField());
        objMap.put("tableRelateField", config.getTableRelateField());
        objMap.put("relateTablePropertyName", config.getRelateTablePropertyName());
        objMap.put("tableRelatePropertyName", config.getTableRelatePropertyName());
        objMap.put("relateTableSqlField", config.getRelateTableSqlField());
        objMap.put("relateModelName", config.getRelateModelName());
        objMap.put("relateModelNameFirstLower", config.getRelateModelNameFirstLower());

        if (configInternal.getOtherConfig() != null)
            objMap.putAll(configInternal.getOtherConfig());
    }

    protected void write(Map<String, Object> dataResult, String templatePath,
                         String outputPath, String outputFileName) {
        VelocityContext context = new VelocityContext(dataResult);
        Template template = velocityEngine.getTemplate(templatePath);

        try {
            File outpuDir = new File(outputPath);
            if (!outpuDir.exists())
                outpuDir.mkdirs();

            Writer writer = new FileWriter(new File(outpuDir, outputFileName));

            template.merge(context, writer);

            System.out.println(outputPath);

            writer.flush();

            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public void generatorMapper(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.MAPPER_PATH);
        String filename = configInternal.getNames().get(Const.MAPPER_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.MAPPER_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorXml(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.XML_PATH);
        String filename = configInternal.getNames().get(Const.XML_CLASS_NAME) + ".xml";

        String baseColumnList = "";
        for (Field field : configInternal.getPoFields()) {
            baseColumnList += field.getColumnName() + ",";
        }
        objMap.put("baseColumnList", baseColumnList.substring(0, baseColumnList.length() - 1));
        write(objMap, configInternal.getTemplatePath().get(Const.XML_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorService(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.SERVICE_PATH);
        String filename = configInternal.getNames().get(Const.SERVICE_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.SERVICE_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorServiceImpl(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.SERVICE_IMPL_PATH);
        String filename = configInternal.getNames().get(Const.SERVICE_IMPL_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.SERVICE_IMPL_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorController(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.CONTROLLER_PATH);
        String filename = configInternal.getNames().get(Const.CONTROLLER_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.CONTROLLER_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorPo(ConfigInternal configInternal) {
        objMap.put("entityType", "po");

        String outputPath = configInternal.getPathInfo().get(Const.PO_PATH);
        String filename = configInternal.getNames().get(Const.PO_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.PO_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorPojo(ConfigInternal configInternal) {
        objMap.put("entityType", "pojo");

        String outputPath = configInternal.getPathInfo().get(Const.POJO_PATH);
        String filename = configInternal.getNames().get(Const.POJO_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.POJO_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorVo(ConfigInternal configInternal) {
        objMap.put("entityType", "vo");

        String outputPath = configInternal.getPathInfo().get(Const.VO_PATH);
        String filename = configInternal.getNames().get(Const.VO_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.VO_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorQueryForm(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.QUERY_FORM_PATH);
        String filename = configInternal.getNames().get(Const.QUERY_FORM_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.QUERY_FORM_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorEditForm(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.EDIT_FORM_PATH);
        String filename = configInternal.getNames().get(Const.EDIT_FORM_CLASS_NAME) + ".java";

        write(objMap, configInternal.getTemplatePath().get(Const.EDIT_FORM_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorVuePage(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.VUE_PAGE_PATH);
        String filename = configInternal.getNames().get(Const.VUE_PAGE_NAME) + ".vue";

        write(objMap, configInternal.getTemplatePath().get(Const.VUE_PAGE_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public void generatorVueApi(ConfigInternal configInternal) {
        String outputPath = configInternal.getPathInfo().get(Const.VUE_API_PATH);
        String filename = configInternal.getNames().get(Const.VUE_API_NAME) + ".js";

        write(objMap, configInternal.getTemplatePath().get(Const.VUE_API_TEMPLATE),
                outputPath, filename);

        generatorFiles.add(new GeneratorFile(filename, outputPath + File.separator + filename));
    }

    public abstract void generatorVueRoute(ConfigInternal configInternal);

}
